using System;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using Mono.Unix;

namespace guessSquare
{
	class MainClass
	{
		internal static string programPath=Assembly.GetEntryAssembly().Location;
		internal static string programName=System.Text.RegularExpressions.Regex.Replace(programPath,@"^.*[/\\]","");
		internal static Stopwatch timer;
		internal static Random rnd=new Random(Environment.TickCount);
		internal static int[] data;
		const int pitch=100;
		const int height=800;
		
		internal static List<double> compressRatioList=new List<double>();
		
		// 幅を要素とするlist<int>を並べ替えないで、その組み合わせの最大幅がint32内に収まるかどうかを判定する
		// return値が>=0の場合はint32内に収まる。<0の場合は収まらない(組み合わせ数が多すぎる)
		//
		// 改善余地あり:組み合わせ数分のloopを回さないと最大幅が算出できない
		// 
		public static void Main(string[] args)
		{
			Catalog.Init("guessSquare","./");
			timer=new Stopwatch();
			timer.Start();
			Console.WriteLine("program: "+programName);
			if(args.Length!=1){
				Console.WriteLine("Usage: {0} <max_loops>",programName);
				Environment.Exit(-1);
			}
			
			//
			MainClass _mainClass=new MainClass();
			for(int i=0;i<int.Parse(args[0]);++i){
				_mainClass.initData();
				_mainClass.guessSquare(0,0,true);
			}
			compressRatioList.Sort(delegate(double a, double b){
				if(a<b) return -1;
				else if(a>b) return 1;
				return 0;
			});
			double sum=0;
			compressRatioList.ForEach(delegate(double a){
				sum += a;
			});
			Console.WriteLine("compress ratio min: {0}, max: {1}, ave: {2}",
			                  compressRatioList[0],compressRatioList[compressRatioList.Count-1],
			                  sum/compressRatioList.Count);
			timer.Stop();
			Console.WriteLine(Catalog.GetString("total elapsed time: ")+timer.Elapsed);
		}
		
		internal void initData(){
			int size=rnd.Next(10,21);
			data=new int[size];
			Console.Write("data: ");
			for(int i=0;i<size;++i){
				data[i]=rnd.Next(1,21);
				Console.Write("{0} ",data[i]);
			}
			Console.WriteLine("(size={0})",data.Length);
		}
		
		internal long guessSquare(int x, int y, bool useDouble){
			long xmax=x,ymax=y,xcombimax=0;
			long average=0;
			
			//Array.Sort(data);
			
			// 一度、最大幅を算出するため組み合わせ計算を行う
			for(int i=0;i<data.Length;++i){
				long linewidth=0;
				for(int j=i;j<data.Length;++j){
					// 要素i,jの組み合わせの幅。6は要素i,jで生成する幅
					long curwidth=(data[i]+data[j])*6;
					// 1つの組み合わせの最大幅の更新(この値の1/2を1ラインあたりの制限幅に設定する)
					if(xcombimax<curwidth) xcombimax=curwidth;
					linewidth += curwidth;
				}
				// 要素i,jでの組み合わせ総幅の更新
				if(xmax<linewidth) xmax=linewidth;
			}
			xmax *= pitch;
			ymax=data.Length*height;
			if(!useDouble){
				average=(xmax+ymax)/2;
			}else{
				average=(long) Math.Sqrt(((double) xmax) * ((double) ymax));
			}
			Console.WriteLine("width: {0}, height {1}, ave {2}, xcombimax {3}",xmax,ymax,average,xcombimax);
			long guessxmax=average-xcombimax/2;
			double compressRatio=((double) xmax)/guessxmax;
			Console.WriteLine("guessXmax: {0} (compress ratio: {1,0:f5})",guessxmax,compressRatio);
			compressRatioList.Add(compressRatio);
			if(x+average>Int32.MaxValue){
				Console.WriteLine("ERR: placing x position ({0}) is overflow in range int32 (4-bytes)",x+average);
				average=-1;
			}else if(y+average>Int32.MaxValue){
				Console.WriteLine("ERR: placing y position ({0}) is overflow in range int32 (4-bytes)",y+average);
				average=-1;
			}
			return average;
		}
	}
}